package com.maycurobj.controller.opdca;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.maycur.developer.sdk.common.exception.MaycurException;
import com.maycur.developer.sdk.maycur.ultimate.openapi.response.PostReceiveApplicationResponse;
import com.maycur.developer.sdk.maycur.ultimate.openapi.response.form.GetFormPreconsumeResponse;
import com.maycurobj.domain.maycurDTO.BpmItineraryDTO;
import com.maycurobj.domain.maycurDTO.MayCurValidation;
import com.maycurobj.domain.maycurDTO.MultipleParticipantsDTO;
import com.maycurobj.entity.bpm.JobNumberDTO;
import com.maycurobj.entity.bpm.ParticipantDTO;
import com.maycurobj.pojo.RepeatedInformation;
import com.maycurobj.repository.bpm.JobNumberMapper;
import com.maycurobj.repository.bpm.ParticipantMapper;
import com.maycurobj.repository.bpm.SalePlanOPDCAMapper;
import com.maycurobj.repository.oa.OASecurityLevelRepository;
import com.maycurobj.service.impl.CrmSerivceImpl;
import com.maycurobj.service.impl.opdca.OPDCAServiceImpl;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeoutException;

import static com.maycurobj.util.opdca.OpdcaUtil.resultMap;

/**
 * 每刻外部关联单据 接口
 * ---OPDCA
 */
@Controller
@RequestMapping("/maycur/opdcaservice")
@Slf4j
public class MaycurOPDCAController {

    @Autowired
    private OPDCAServiceImpl opdcaService;

    @Autowired
    private JobNumberMapper convertJobNumber;

    @Autowired
    private ParticipantMapper participantMapper;

    @Autowired
    private SalePlanOPDCAMapper salePlanOPDCAMapper;

    @Autowired
    private OASecurityLevelRepository oaSecurityLevelRepository;
    @Autowired
    private CrmSerivceImpl crmSerivce;

    private ExecutorService executorService = Executors.newFixedThreadPool(10);

    //rabbitmq 队列配置
    private String HOST_NAME = "172.17.100.71";
    private Integer HOST_PORT=5672;
    private String USER_NAME = "admin";
    private String PASSWORD = "Bio-San@17";
    private static final String DLX_EXCHANGE = "dlx_exchange";
    private static final String NORMAL_QUEUE = "normal_queue";
    private static final String MAY_CUR_VIRTUAL_HOST = "/maycur_business";

    /**
     * 接收BPM 行程请求 itinerary receive
     * 推送到每刻的 申请单 formSubTypeBizCode=FT61371951729350755
     *
     * @param entity
     * @return
     */
    @PostMapping("/receiveBpmTravel")
    @ResponseBody
    public Map<String, Object> receiveBpmTravel(@RequestBody Map<String, Object> entity) {
        log.info("打印Bpm发出的行程---->{}", JSONObject.toJSONString(entity));
        BpmItineraryDTO dto = JSONObject.parseObject(JSONObject.toJSONString(entity), BpmItineraryDTO.class);
        List<String> cities = new ArrayList<>();
        cities.add(dto.getToCityId());
        convertDesCity(dto, cities);
        dto.setToCityIds(cities);
        List<MultipleParticipantsDTO> list = dto.getParticipants();
        if (!Objects.isNull(dto.getParticipants())) {
            List<JobNumberDTO> job = new ArrayList<>();
            for (MultipleParticipantsDTO list1 : list) {
                job.add(convertJobNumber.getUserID(list1.getId()));
            }
            dto.setJobNumber(job);
        }

        //整理行程 推送
        PostReceiveApplicationResponse response = null;
        try {
            dto.setNewFormCode(dto.getFormCode());
            response = opdcaService.importReferenceToMayCur(dto);
            if (!Objects.isNull(dto.getJobNumber())) {
                int i = 0;

                for (JobNumberDTO _s : dto.getJobNumber()) {
                    if (!_s.equals(dto.getEmpNo())) {
                        dto.setEmpNo(_s.getEmployeeNo());
                        dto.setNewFormCode(dto.getFormCode() + "--" + i);
                        response = opdcaService.importReferenceToMayCur(dto);
                        i++;
                    }
                }
            }
            //返回的可能不会直接更新到字段中 通过服务层的方法接口回写
            Map<String, Object> ret = resultMap(response.getCode(), JSONObject.toJSONString(response), response.getData());
            Map<String, Object> ret2 = new HashMap<>();
            ret2.put("id", dto.getObjId());
            ret2.put("responseMsg", JSONObject.toJSONString(response));
            opdcaService.updateBpmOPDCAEntity(JSONObject.toJSONString(ret2));
            log.info("打印返回值:---->>>>{}", JSONObject.toJSONString(ret));
            return ret;
        } catch (Exception e) {
            log.info("receiveBpmTravel---->>>每刻推送异常(每刻系统出现故障)进入重试机制,通知管理员{}");
            //消息处理失败进入队列
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost(HOST_NAME);
            factory.setPort(HOST_PORT);
            factory.setUsername(USER_NAME);
            factory.setPassword(PASSWORD);
            factory.setVirtualHost(MAY_CUR_VIRTUAL_HOST);
            try {
                Connection rabbitMQConnection = factory.newConnection();
                Channel channel = rabbitMQConnection.createChannel();
                Map<String, Object> headers = new HashMap<>();
                int retryCount = 0;
                headers.put("x-retry-count", retryCount + 1);
                headers.put("x-death-reason", "first_retry");
                AMQP.BasicProperties newProperties = new AMQP.BasicProperties.Builder()
                        .headers(headers)
                        .build();
                //发送到第一次延时队列
                channel.basicPublish(DLX_EXCHANGE, "retry_5m", newProperties, JSONObject.toJSONBytes(entity));
            } catch (IOException ex) {
                log.info("rabbitmq链接参数配置异常");
            } catch (TimeoutException ex) {
                log.info("rabbitmq链接超时");
            }

            return resultMap("error", "中间件反馈==>每刻推送异常(每刻系统出现故障),通知管理员", null);
        }
    }

    /**
     * 检查行程是否重复
     * @param entity
     * @return
     * @throws Exception
     */
    @PostMapping("/tripcheck")
    @ResponseBody
    public Map<String,Object> tripCheck(@RequestBody Map<String, Object> entity){
        log.info("获取到的内容---->{}", JSONObject.toJSONString(entity));
        BpmItineraryDTO dto = JSONObject.parseObject(JSONObject.toJSONString(entity), BpmItineraryDTO.class);
        List<MultipleParticipantsDTO> list = dto.getParticipants();

        if (!Objects.isNull(dto.getParticipants())) {
            List<RepeatedInformation> repeatedInformationlist = new ArrayList<>();
            Map<String, Object> ret2 = new HashMap<>();
            //检查参与人行程是否重复
            handleParticipants(list, repeatedInformationlist, dto);
            //数据库获取客户拜访时间段内数据
            List<ParticipantDTO> accountlist = participantMapper.getAccountResults(dto.getNew_account_name(), dto.getNew_date_start(), dto.getNew_date(), dto.getObjId());
            //检查客户是否重复拜访
            handleAccountlist(accountlist, repeatedInformationlist, dto);
            ret2.put("code", 200);
            ret2.put("data", repeatedInformationlist);
            return ret2;
        }
        return null;
    }

    /**
     * 检查参与人行程是否重复
     */
    private void handleParticipants(List<MultipleParticipantsDTO> list, List<RepeatedInformation> repeatedInformationlist, BpmItineraryDTO dto) {
        for (MultipleParticipantsDTO list1 : list) {
            List<ParticipantDTO> job = participantMapper.getSimilarResults(("%" + list1.getId() + "%"), dto.getNew_date_start(), dto.getNew_date(), dto.getObjId());
                for (ParticipantDTO list2 : job) {
                    RepeatedInformation repeatedInformation = new RepeatedInformation();
                    repeatedInformation.setName(list1.getName());
                    repeatedInformation.setSubject(list2.getSubject());
                    repeatedInformation.setSequenceNo(list2.getSequenceNo());
                    repeatedInformationlist.add(repeatedInformation);
                }
        }
    }

    /**
     * 检查客户是否重复拜访
     */
    private void handleAccountlist(List<ParticipantDTO> accountlist, List<RepeatedInformation> repeatedInformationlist, BpmItineraryDTO dto) {
        if (!accountlist.isEmpty()) {
            for (ParticipantDTO list2 : accountlist) {
                RepeatedInformation repeatedInformation = new RepeatedInformation();
                repeatedInformation.setName(dto.getNew_account_name());
                repeatedInformation.setSequenceNo(list2.getSequenceNo());
                repeatedInformationlist.add(repeatedInformation);
            }
        }
    }

    /**
     * 新增 中转城市 到目的城市中
     *
     * @param dto
     * @param cities
     */
    private void convertDesCity(BpmItineraryDTO dto, List<String> cities) {
        try {
            if (!Objects.isNull(dto.getPassing_through_cities())) {
                String str = dto.getPassing_through_cities().get("id").toString();
                String[] array = str.split(";");
                for (String list1 : array) {
                    cities.add(salePlanOPDCAMapper.getToCityId(list1));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info("convertDesCity 方法有异常");
        }
    }

    /**
     * 接收BPM 行程请求 手动版 只接受 objid
     * 推送到每刻的 申请单 formSubTypeBizCode=FT61371951729350755
     *
     * @param objId
     * @return
     */
    @PostMapping("/manualHandleBpmTravel")
    @ResponseBody
    public String manualHandleBpmTravel(@RequestParam String objId) {
        log.info("打印接受到的bpm opdca id---->{}", objId);
        String ret = opdcaService.manualHandleBpmTravelService(objId);
        return ret;
    }

    /**
     * 接收BPM 行程请求 手动版 只接受 objid
     * 推送到每刻的 申请单 formSubTypeBizCode=FT61371951729350755
     *
     * @param seqNo
     * @return
     */
    @PostMapping("/manualHandleBpmTravelBySeqNo")
    @ResponseBody
    public String manualHandleBpmTravelBySeqNo(@RequestParam String seqNo) {
        log.info("打印接受到的bpm opdca id---->{}", seqNo);
        String ret = opdcaService.manualHandleBpmTravelBySeqNoService(seqNo);
        return ret;
    }

    /**
     * 停用 每刻行程单
     *
     * @param code 格式 preConsumeCode:xx
     */
    @PostMapping("/disableBpmTravel")
    @ResponseBody
    public synchronized Map<String, Object> disableBpmTravel(@RequestParam("code") String code) {
        log.info("每刻行程单---{}", JSONObject.toJSONString(code));
        //执行停用
        try {
            String ret = opdcaService.disableReferenceToMayCur(code);
            return JSONObject.parseObject(ret, HashMap.class);
        } catch (Exception e) {
            return resultMap("-1", "中间件执行异常！", null);
        }
    }

    /**
     * 作废 每刻行程单
     *
     * @param code 格式 preConsumeCode:xx
     */
    @PostMapping("/nullBpmTravel")
    @ResponseBody
    public synchronized Map<String, Object> nullBpmTravel(@RequestParam("code") String code) {
        log.info("每刻行程单---{}", JSONObject.toJSONString(code));
        //执行停用
        try {
            String ret = opdcaService.nullReferenceToMayCur(code);
            return JSONObject.parseObject(ret, HashMap.class);
        } catch (Exception e) {
            return resultMap("-1", "中间件执行异常！", null);
        }
    }

    /**
     * 请求 每刻行程单(申请单内) 对象
     *
     * @param code
     * @return
     */
    @PostMapping("/getBpmItinerary")
    @ResponseBody
    public Map<String, Object> getIteineraryFromMaycur(@RequestParam String code) {
        ///api/openapi/form/preconsume/{formCode}
        log.info("打印接收到的code-----?{}", code);
        if (StringUtils.isBlank(code)) {
            return resultMap("error", "入参异常", null);
        }
        try {
            GetFormPreconsumeResponse response = opdcaService.getMayCurPreconsume(code);
            return resultMap(response.getCode(), response.getMessage(), response.getData());
        } catch (MaycurException e) {
            return resultMap("error", "中间件异常,通知管理员" + e.getMessage(), null);
        }
    }


    /**
     * 每刻报销提交时 触发博圣自定义校验
     * source maycur
     */
    @PostMapping("/handleSaleReportsValidation")
    @ResponseBody
    public Map<String, Object> maycurValidationForCustom(@RequestBody JSONObject entity) {
        log.info("获取到 每刻自定义校验 报文---->{}", JSONObject.toJSONString(entity));

        JSONObject formData = entity.getJSONObject("formData");

        List<Map<String, Object>> ret = opdcaService.validationForCustom(formData);

//        validationResponse(ret);
//        return defaultMapForValidation();
        return validationResponse(ret);
    }

    /**
     *每刻单据完成，自动停用申请单
     * @param entity
     * @return
     */
    @PostMapping("/stoprequest")
    @ResponseBody
    public JSONObject stopRequest(@RequestBody JSONObject entity) {
        // 获取实体
        JSONObject jsonObject = new JSONObject(entity);
        // 获取列表
        try {
            JSONArray travelRouteList = jsonObject.getJSONObject("formData").getJSONObject("travelRouteList").getJSONArray("value");
            String code = null;
            // 遍历列表
            for (int i = 0; i < travelRouteList.size(); i++) {
                // 获取当前 map
                JSONObject mapObject = travelRouteList.getJSONObject(i);
                // 获取code
                code=getCode(mapObject);
                // 如果code不为空，则禁用参考当前
                // 如果code不为空，则异步禁用参考当前
                if (StringUtils.isNotBlank(code)) {
                    String finalCode = code;
                    executorService.submit(() -> {
                        try {
                            opdcaService.disableReference(finalCode);
                        } catch (Exception e) {
                            log.error("禁用参考失败，code: " + finalCode, e);
                        }
                    });
                }
            }
            // 返回结果
            JSONObject ret = new JSONObject();
            ret.put("success", true);
            ret.put("errorMsg", "成功");
            return ret;
        }catch (Exception e){
            log.info("该单据没有关联行程！");
            // 返回结果
            JSONObject ret = new JSONObject();
            ret.put("success", true);
            ret.put("errorMsg", "成功");
            return ret;
        }
    }

    /**
     * 获取json中的code
     * @param jsonObject
     * @return
     */
    private String getCode(JSONObject jsonObject) {
        try {
            //获取JSONObject中的customObject对象
            String code = jsonObject.getJSONObject("customObject").getJSONObject("CF245").getJSONObject("value").getString("text");
            //返回获取到的字符串
            return code;
        } catch (Exception e) {
            //如果发生异常，则返回null
            return null;
        }
    }

    /**
     * 每刻报销时 差旅费 一般费用报销,触发自定义校验
     */
    @PostMapping("/handleReimburseValidation")
    @ResponseBody
    public Map<String, Object> handleReimburseValidation(@RequestBody JSONObject entity) {
//        log.info("获取到 每刻自定义校验 报文---->{}", JSONObject.toJSONString(entity));
        //获取用户工号
        String empNo = getFillUser(entity);
        //获取OA安全级别
        Integer seclevel = oaSecurityLevelRepository.getSeclevel(empNo);

        //log.info("请求报文--->{}",entity.toString());
        JSONObject formData = entity.getJSONObject("formData");

        //转换用户crmid 同时比较 在服务层处理
        Map<String, Object> ret = crmSerivce.getUserHasCrmRoleCustomer(empNo, formData);
        //返回结果
        return validationResponse2(ret,seclevel);
    }


    private String getFillUser(JSONObject entity) {
        try {
            JSONObject formData = entity.getJSONObject("formData");
            JSONObject fillUser = formData.getJSONObject("fillUser");
            JSONObject fillUserValue = (JSONObject) fillUser.getJSONArray("value").get(0);
            return fillUserValue.getString("employeeNo");
        } catch (Exception e) {
            e.printStackTrace();
            log.info("制单人获取异常---->>>>");
            return null;
        }
    }

    /**
     * 处理手动导入OPDCA行程单的校验
     * 24年1月作为缓冲期 暂不执行
     * 24年3月开始 严控 (增加手动处理入参)
     *
     * @return
     */
    @PostMapping("/handleImportOPDCA")
    @ResponseBody
    public Map<String, Object> handleImportOPDCA(@RequestBody JSONObject entity) {
        log.info("获取每刻行程按钮：{}", JSONObject.toJSONString(entity));
        if (avoidHandleImportOPDCA(entity)) {
            Map<String, Object> validation = new HashMap<>();
            validation.put("message", "手动补录行程成功");
            validation.put("targetClassify", "FORM");
            validation.put("needReason", false);
            List<Map<String, Object>> validations = new ArrayList<>();
            validations.add(validation);
            Map<String, Object> validationResult = new HashMap<>();
            validationResult.put("validationResult", validations);
            JSONObject retJson = new JSONObject();

            retJson.put("errorMsg", "手动补录行程成功");
            retJson.put("success", true);
            retJson.put("data", validationResult);
            log.info("测试---返回行程信息服务:{}", retJson.toJSONString());

            return retJson;
        } else {
            Map<String, Object> validation = new HashMap<>();
            validation.put("message", "禁止在报销时创建行程，请从'访客计划'中创建行程或导入OPDCA行程");
            validation.put("targetClassify", "FORM");
            validation.put("needReason", false);
            List<Map<String, Object>> validations = new ArrayList<>();
            validations.add(validation);
            Map<String, Object> validationResult = new HashMap<>();
            validationResult.put("validationResult", validations);
            JSONObject retJson = new JSONObject();

            retJson.put("errorMsg", "禁止在报销时创建行程，请从'访客计划'中创建行程或导入OPDCA行程");
            retJson.put("success", false);
            retJson.put("data", validationResult);
            log.info("测试---返回行程信息服务:{}", retJson.toJSONString());

            return retJson;
        }

    }

    /**
     * 手动 增加每刻行程 规避机制  如果填写(avoid行程) 可以绕过
     * 增加 参加培训,参加内部会议
     * 返回false 不可以绕过
     *
     * @param entity
     * @return
     */
    private boolean avoidHandleImportOPDCA(JSONObject entity) {
        //检查报文信息
        try {
            if (entity.containsKey("CF201")) {
                JSONObject jsonObject = entity.getJSONObject("CF201");
                JSONObject valueObject = jsonObject.getJSONObject("value");
                if (StringUtils.isNotBlank(valueObject.getString("text"))) {
                    String _text = valueObject.getString("text");
                    if (_text.contains("avoid行程") || _text.equals("参加培训") || _text.equals("参加内部会议")) {
                        return true;
                    }
                }
            }
            return false;
        } catch (Exception e) {
            return false;
        }
    }


    //联调时，使用默认返回
    @Deprecated
    private Map<String, Object> defaultMapForValidation() {
        List<MayCurValidation> list = new ArrayList<>();
        MayCurValidation validation = new MayCurValidation();
        validation.setLevel("ERROR"); //error 无法提交
        validation.setMessage("行程无法匹配");
        validation.setTargetClassify("FORM");
        validation.setTargetCode(null);
        validation.setNeedReason(false);
        list.add(validation);
        Map<String, Object> validationResult = new HashMap<>();
        validationResult.put("validationResult", list);
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("validationResult", list);
        dataMap.put("errorMsg", "success");
        dataMap.put("success", true);
        dataMap.put("data", validationResult);
        return dataMap;
    }

    /**
     * 正式环境 返回值
     * validation.setLevel("ERROR"); //error 无法提交
     * validation.setLevel("WARNING"); //WARNING 可以提交
     *
     * @param list
     * @return
     */
    private Map<String, Object> validationResponse(List<Map<String, Object>> list) {
        List<MayCurValidation> validations = new ArrayList<>();
        for (Map<String, Object> _map : list) {
            MayCurValidation validation = new MayCurValidation();
            //根据管控权限 进行限制
            if (Boolean.valueOf(_map.get("code").toString())) {
                //code = true 可以提交，理由的填写根据返回的字符串的提示(是否含有通过)进行控制
                validation.setLevel("WARNING");
                if (_map.get("message").toString().indexOf("通过") > 0) {
                    validation.setNeedReason(false);
                } else {
                    //如果有提示异常,但为弱控的 用true填写理由提交
                    validation.setNeedReason(true);
                }
                validation.setMessage(_map.get("message").toString());
            } else {
                validation.setLevel("ERROR"); //24年1月份为过渡期 暂时不控制 可以提交，需要理由 24年3月开始 调整该行
                validation.setNeedReason(true);
                validation.setMessage(_map.get("message").toString());
            }
            validation.setTargetClassify("FORM");
            validation.setTargetCode(null);
            validations.add(validation);
        }
        Map<String, Object> validationResult = new HashMap<>();
        validationResult.put("validationResult", validations);
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("errorMsg", "success");
        dataMap.put("success", true);
        dataMap.put("data", validationResult);
        return dataMap;
    }

    /**
     * 正式环境 客户权限 校验返回值
     * validation.setLevel("ERROR"); //error 无法提交
     * validation.setLevel("WARNING"); //WARNING 可以提交
     *
     * @param map
     * @return
     */
    private Map<String, Object> validationResponse2(Map<String, Object> map,Integer seclevel) {
        List<MayCurValidation> validations = new ArrayList<>();
        MayCurValidation validation = new MayCurValidation();
        if (map.isEmpty() || seclevel.equals(25) || seclevel.equals(45)) {
            //不需要理由,可以提交
            Map<String, Object> validationResult = new HashMap<>();
            validationResult.put("validationResult", null);
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("errorMsg", "success");
            dataMap.put("success", true);
            dataMap.put("data", validationResult);
            return dataMap;
        } else {
            //需要理由,可以提交
            StringBuilder sb = new StringBuilder();
            validation.setNeedReason(true);
            map.entrySet().stream().forEach(e -> {
                sb.append(e.getKey() + ",");
            });
            validation.setMessage("客户选择范围校验不通过!如下客户您无权限选择:" + sb.toString());
            validation.setLevel("WARNING");
            validation.setTargetClassify("FORM");
            validation.setTargetCode(null);
            validations.add(validation);
            Map<String, Object> validationResult = new HashMap<>();
            validationResult.put("validationResult", validations);
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("errorMsg", "success");
            dataMap.put("success", true);
            dataMap.put("data", validationResult);
            return dataMap;
        }
    }


    /**
     * 作废不用
     *
     * @param entity
     * @return
     */
    @PostMapping("/getSaleReports")
    @ResponseBody
    @Deprecated
    public JSONObject getSaleReports(@RequestBody Map<String, Object> entity) {
        log.info("测试---获取每刻行程按钮：{}", JSONObject.toJSONString(entity));

        Map<String, Object> validation = new HashMap<>();
        validation.put("message", "禁止在报销时创建行程，请从'访客计划'中创建行程!");
        validation.put("targetClassify", "FORM");
        validation.put("needReason", false);
        List<Map<String, Object>> validations = new ArrayList<>();
        validations.add(validation);
        Map<String, Object> validationResult = new HashMap<>();
        validationResult.put("validationResult", validations);
        JSONObject retJson = new JSONObject();
        OPDCAServiceImpl opdcaService = new OPDCAServiceImpl();

        retJson.put("errorMsg", "禁止在报销时创建行程，请从'访客计划'中创建行程!");
        retJson.put("success", false);
        retJson.put("data", validationResult);
        log.info("测试---返回行程信息服务:{}", retJson.toJSONString());

        return retJson;
    }

}
